package io.modelcontextprotocol.sdk;

import io.modelcontextprotocol.json.McpJsonMapper;
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpSyncServerExchange;
import io.modelcontextprotocol.spec.McpSchema;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
 * 聊天MCP服务器 - 提供聊天记录和发送消息功能
 */
public class ChatMcpServer {

    private static final Logger logger = LoggerFactory.getLogger(ChatMcpServer.class);

    private static final String SERVER_NAME = "Chat MCP Server";
    private static final String SERVER_VERSION = "1.0.0";
    private static final int PORT = 8081;

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
    private final java.util.concurrent.ExecutorService asyncExecutor = Executors.newFixedThreadPool(4);
    private final java.util.concurrent.atomic.AtomicBoolean stopping = new java.util.concurrent.atomic.AtomicBoolean(false);

    private NanoHttpdSseServerTransportProvider transportProvider;
    private final McpJsonMapper jsonMapper = McpJsonMapper.getDefault();

    public static void main(String[] args) {
        ChatMcpServer server = new ChatMcpServer();
        try {
            server.start();
            logger.info("🚀 聊天MCP服务器启动成功！");
            logger.info("📡 SSE端点: http://localhost:{}/sse", PORT);
            logger.info("📨 消息端点: http://localhost:{}/message", PORT);
            logger.info("🔧 可用工具:");
            logger.info("  - get_all_conversations: 获取所有聊天记录");
            logger.info("  - get_conversation_by_id: 根据ID获取聊天记录");
            logger.info("  - get_messages_by_conversation_id: 根据会话ID获取消息列表");
            logger.info("  - send_message: 发送消息");
            logger.info("  - broadcast_message: 向所有客户端广播消息");
            logger.info("  - send_to_client: 向指定客户端推送消息");
            logger.info("  - get_connected_clients: 获取所有在线客户端列表");
            logger.info("  - ping: 检测服务器连接状态");
            logger.info("  - disconnect: 客户端主动断开连接");

            // 简单驻留，直到进程结束
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        } catch (Exception e) {
            logger.error("❌ 服务器启动失败", e);
        } finally {
            try {
                server.stop();
            } catch (Exception ignored) {
            }
        }
    }

    public void start() throws Exception {
        logger.info("💬 初始化聊天MCP服务器...");

        // 1) 构建基于 NanoHTTPD 的 MCP SSE 传输提供者
        this.transportProvider = NanoHttpdSseServerTransportProvider
                .builder()
                .port(PORT)
                .messageEndpoint("/message")
                .sseEndpoint("/sse")
                .build();

        // 2) 基于McpServer构建同步MCP服务，注册工具
        McpServer
                .sync(transportProvider)
                .serverInfo(SERVER_NAME, SERVER_VERSION)
                .toolCall(createGetAllConversationsTool(), this::handleGetAllConversations)
                .toolCall(createGetConversationByIdTool(), this::handleGetConversationById)
                .toolCall(createGetMessagesByConversationIdTool(), this::handleGetMessagesByConversationId)
                .toolCall(createSendMessageTool(), this::handleSendMessage)
                .toolCall(createBroadcastMessageTool(), this::handleBroadcastMessage)
                .toolCall(createSendToClientTool(), this::handleSendToClient)
                .toolCall(createGetConnectedClientsTool(), this::handleGetConnectedClients)
                .toolCall(createPingTool(), this::handlePing)
                .toolCall(createDisconnectTool(), this::handleDisconnect)
                .build();

        logger.info("✅ 聊天MCP服务器启动完成");
    }

    public void stop() {
        if (stopping.compareAndSet(false, true)) {
            logger.info("🛑 正在停止 ChatMcpServer...");
            try {
                if (transportProvider != null) {
                    transportProvider.closeGracefully().block();
                }
            } catch (Exception e) {
                logger.warn("停止传输提供者时出错: {}", e.toString());
            }
            try {
                asyncExecutor.shutdownNow();
            } catch (Exception ignored) {
            }
            try {
                scheduler.shutdownNow();
            } catch (Exception ignored) {
            }
            logger.info("✅ ChatMcpServer 已停止");
        }
    }

    /**
     * 创建获取所有聊天记录的工具
     */
    private McpSchema.Tool createGetAllConversationsTool() {
        return McpSchema.Tool.builder()
                .name("get_all_conversations")
                .description("获取所有聊天记录")
                .inputSchema(new McpSchema.JsonSchema("object",
                        Map.of(), List.of(), null, null, null))
                .build();
    }

    /**
     * 创建根据ID获取聊天记录的工具
     */
    private McpSchema.Tool createGetConversationByIdTool() {
        return McpSchema.Tool.builder()
                .name("get_conversation_by_id")
                .description("根据ID获取聊天记录")
                .inputSchema(new McpSchema.JsonSchema("object", // McpSchema.JsonSchema("object", ...) 创建一个 JSON Schema 对象，类型为 "object"
                        // Map.of(...) - 属性定义
                        Map.of("conversation_id", Map.of("type", "string", "description", "聊天记录ID")),
                        // List.of(...) - 必需字段列表
                        List.of("conversation_id"),
                        // null, null, null - 其他参数
                        null, null, null))
                .build();
    }

    /**
     * 创建发送消息的工具
     */
    private McpSchema.Tool createSendMessageTool() {
        return McpSchema.Tool.builder()
                .name("send_message")
                .description("发送消息到指定聊天记录")
                .inputSchema(new McpSchema.JsonSchema("object",
                        Map.of(
                                "conversation_id", Map.of("type", "string", "description", "聊天记录ID"),
                                "sender", Map.of("type", "string", "description", "发送者"),
                                "content", Map.of("type", "string", "description", "消息内容")
                        ),
                        List.of("conversation_id", "sender", "content"), null, null, null))
                .build();
    }

    /**
     * 创建根据会话ID获取消息列表的工具
     */
    private McpSchema.Tool createGetMessagesByConversationIdTool() {
        return McpSchema.Tool.builder()
                .name("get_messages_by_conversation_id")
                .description("根据会话ID获取消息列表")
                .inputSchema(new McpSchema.JsonSchema("object",
                        Map.of("conversation_id", Map.of("type", "string", "description", "会话ID")),
                        List.of("conversation_id"), null, null, null))
                .build();
    }

    /**
     * 创建广播消息工具
     */
    private McpSchema.Tool createBroadcastMessageTool() {
        return McpSchema.Tool.builder()
                .name("broadcast_message")
                .description("向所有连接的客户端广播消息")
                .inputSchema(new McpSchema.JsonSchema("object",
                        Map.of(
                                "title", Map.of("type", "string", "description", "广播消息标题"),
                                "message", Map.of("type", "string", "description", "广播消息内容")
                        ),
                        List.of("title", "message"), null, null, null))
                .build();
    }

    /**
     * 创建向指定客户端发送消息的工具
     */
    private McpSchema.Tool createSendToClientTool() {
        return McpSchema.Tool.builder()
                .name("send_to_client")
                .description("向指定的客户端推送消息")
                .inputSchema(new McpSchema.JsonSchema("object",
                        Map.of(
                                "session_id", Map.of("type", "string", "description", "客户端会话ID"),
                                "title", Map.of("type", "string", "description", "消息标题"),
                                "message", Map.of("type", "string", "description", "消息内容")
                        ),
                        List.of("session_id", "title", "message"), null, null, null))
                .build();
    }

    /**
     * 创建获取在线客户端列表的工具
     */
    private McpSchema.Tool createGetConnectedClientsTool() {
        return McpSchema.Tool.builder()
                .name("get_connected_clients")
                .description("获取所有在线客户端的会话ID列表")
                .inputSchema(new McpSchema.JsonSchema("object",
                        Map.of(), List.of(), null, null, null))
                .build();
    }

    /**
     * 创建ping工具
     */
    private McpSchema.Tool createPingTool() {
        return McpSchema.Tool.builder()
                .name("ping")
                .description("发送ping请求检测服务器连接状态")
                .inputSchema(new McpSchema.JsonSchema("object",
                        Map.of(), List.of(), null, null, null))
                .build();
    }

    /**
     * 创建disconnect工具
     */
    private McpSchema.Tool createDisconnectTool() {
        return McpSchema.Tool.builder()
                .name("disconnect")
                .description("客户端主动通知服务器断开连接")
                .inputSchema(new McpSchema.JsonSchema("object",
                        Map.of(), List.of(), null, null, null))
                .build();
    }

    /**
     * 处理获取所有聊天记录的请求
     */
    private McpSchema.CallToolResult handleGetAllConversations(McpSyncServerExchange exchange,
                                                               McpSchema.CallToolRequest request) {
        logger.info("📋 获取所有聊天记录");

        try {
            List<ChatRecord.Conversation> conversations = ChatRecord.getAllConversation();

            StringBuilder result = new StringBuilder();
            result.append("📋 所有聊天记录:\n\n");

            for (ChatRecord.Conversation conversation : conversations) {
                result.append("💬 聊天记录 ID: ").append(conversation.getId()).append("\n");
                result.append("👤 发送者: ").append(conversation.getSender()).append("\n");
                result.append("📝 消息数量: ").append(conversation.getMessages().size()).append("\n");

                // 显示最近的消息
                if (!conversation.getMessages().isEmpty()) {
                    ChatRecord.Message lastMessage = conversation.getMessages().get(conversation.getMessages().size() - 1);
                    result.append("💭 最新消息: ").append(lastMessage.getContent()).append("\n");
                }
                result.append("---\n");
            }

            result.append("\n📊 总计: ").append(conversations.size()).append(" 个聊天记录");

            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent(result.toString())))
                    .isError(false)
                    .build();

        } catch (Exception e) {
            logger.error("❌ 获取聊天记录失败", e);
            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent("❌ 获取聊天记录失败: " + e.getMessage())))
                    .isError(true)
                    .build();
        }
    }

    /**
     * 处理根据ID获取聊天记录的请求
     */
    private McpSchema.CallToolResult handleGetConversationById(McpSyncServerExchange exchange,
                                                               McpSchema.CallToolRequest request) {
        String conversationId = (String) request.arguments().get("conversation_id");
        logger.info("🔍 获取会话记录 ID: {}", conversationId);

        try {
            ChatRecord.Conversation conversation = ChatRecord.getConversationById(conversationId);

            if (conversation == null) {
                return McpSchema.CallToolResult.builder()
                        .content(List.of(new McpSchema.TextContent("❌ 未找到conversationId为 " + conversationId + " 的会话记录")))
                        .isError(true)
                        .build();
            }

            StringBuilder result = new StringBuilder();
            result.append("💬 会话记录详情:\n");
            result.append("🆔 ID: ").append(conversation.getId()).append("\n");
            result.append("👤 发送者: ").append(conversation.getSender()).append("\n");
            result.append("📝 消息数量: ").append(conversation.getMessages().size()).append("\n\n");

            result.append("📋 消息列表:\n");
            for (int i = 0; i < conversation.getMessages().size(); i++) {
                ChatRecord.Message message = conversation.getMessages().get(i);
                result.append(String.format("[%d] %s: %s\n", i + 1, message.getSender(), message.getContent()));
            }

            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent(result.toString())))
                    .isError(false)
                    .build();

        } catch (Exception e) {
            logger.error("❌ 获取聊天记录失败", e);
            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent("❌ 获取聊天记录失败: " + e.getMessage())))
                    .isError(true)
                    .build();
        }
    }

    /**
     * 处理根据会话ID获取消息列表的请求
     */
    private McpSchema.CallToolResult handleGetMessagesByConversationId(McpSyncServerExchange exchange,
                                                                       McpSchema.CallToolRequest request) {
        String conversationId = (String) request.arguments().get("conversation_id");
        logger.info("📋 获取会话消息列表 - 会话ID: {}", conversationId);

        try {
            List<ChatRecord.Message> messages = ChatRecord.getMessageByConversationId(conversationId);

            if (messages == null) {
                return McpSchema.CallToolResult.builder()
                        .content(List.of(new McpSchema.TextContent("❌ 未找到conversationId为 " + conversationId + " 的会话记录")))
                        .isError(true)
                        .build();
            }

            StringBuilder result = new StringBuilder();
            result.append("💬 会话ID: ").append(conversationId).append("\n");
            result.append("📝 消息总数: ").append(messages.size()).append("\n\n");

            if (messages.isEmpty()) {
                result.append("📭 该会话暂无消息");
            } else {
                result.append("📋 消息列表:\n");
                for (int i = 0; i < messages.size(); i++) {
                    ChatRecord.Message message = messages.get(i);
                    result.append(String.format("[%d] %s: %s\n", i + 1, message.getSender(), message.getContent()));
                }
            }

            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent(result.toString())))
                    .isError(false)
                    .build();

        } catch (Exception e) {
            logger.error("❌ 获取消息列表失败", e);
            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent("❌ 获取消息列表失败: " + e.getMessage())))
                    .isError(true)
                    .build();
        }
    }

    /**
     * 处理发送消息的请求
     */
    private McpSchema.CallToolResult handleSendMessage(McpSyncServerExchange exchange,
                                                       McpSchema.CallToolRequest request) {
        String conversationId = (String) request.arguments().get("conversation_id");
        String sender = (String) request.arguments().get("sender");
        String content = (String) request.arguments().get("content");

        // 确保字符串编码正确
        logger.info("📤 发送消息 - 聊天记录ID: {}, 发送者: {}, 内容: {}", conversationId, sender, content);
        logger.debug("原始参数 - conversationId: '{}', sender: '{}', content: '{}'",
                conversationId, sender, content);

        try {
            // 检查聊天记录是否存在
            ChatRecord.Conversation conversation = ChatRecord.getConversationById(conversationId);
            if (conversation == null) {
                return McpSchema.CallToolResult.builder()
                        .content(List.of(new McpSchema.TextContent("❌ 未找到conversationId为 " + conversationId + " 的会话记录")))
                        .isError(true)
                        .build();
            }

            // 发送消息
            ChatRecord.sendMessage(conversationId, sender, content);


            String result = String.format("✅ 消息发送成功!\n" +
                            "💬 会话ID: %s\n" +
                            "👤 发送者: %s\n" +
                            "📝 消息内容: %s\n" +
                            "📊 当前消息总数: %d",
                    conversationId, sender, content, conversation.getMessages().size());

            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent(result)))
                    .isError(false)
                    .build();

        } catch (Exception e) {
            logger.error("❌ 发送消息失败", e);
            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent("❌ 发送消息失败: " + e.getMessage())))
                    .isError(true)
                    .build();
        }
    }

    /**
     * 处理广播消息请求
     */
    private McpSchema.CallToolResult handleBroadcastMessage(McpSyncServerExchange exchange,
                                                            McpSchema.CallToolRequest request) {
        String title = (String) request.arguments().get("title");
        String message = (String) request.arguments().get("message");

        logger.info("📢 广播消息 - 标题: {}, 内容: {}", title, message);

        try {
            // 创建广播消息参数
            Map<String, Object> params = Map.of(
                    "title", title,
                    "message", message,
                    "timestamp", System.currentTimeMillis()
            );

            // 向所有客户端广播
            broadcastToAllClients("notifications/broadcast", params);

            String result = String.format("✅ 广播消息成功!\n" +
                            "📣 标题: %s\n" +
                            "📝 内容: %s\n" +
                            "⏰ 时间: %s",
                    title, message, new java.util.Date());

            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent(result)))
                    .isError(false)
                    .build();

        } catch (Exception e) {
            logger.error("❌ 广播消息失败", e);
            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent("❌ 广播消息失败: " + e.getMessage())))
                    .isError(true)
                    .build();
        }
    }

    /**
     * 处理ping请求
     */
    private McpSchema.CallToolResult handlePing(McpSyncServerExchange exchange,
                                                McpSchema.CallToolRequest request) {
        logger.info("🏓 收到ping请求");


        String result = "🏓 pong! 服务器连接正常...";

        return McpSchema.CallToolResult.builder()
                .content(List.of(new McpSchema.TextContent(result)))
                .isError(false)
                .build();
    }

    /**
     * 处理客户端主动断开连接请求
     */
    private McpSchema.CallToolResult handleDisconnect(McpSyncServerExchange exchange,
                                                      McpSchema.CallToolRequest request) {
        // 获取当前会话的sessionId
        String sessionId = exchange.sessionId();
        logger.info("👋 客户端 {} 主动请求断开连接", sessionId);

        try {
            // 从transportProvider中移除该会话
            if (transportProvider.removeSession(sessionId)) {
                String result = String.format("✅ 客户端断开成功!\n" +
                                "🆔 会话ID: %s\n" +
                                "⏰ 断开时间: %s",
                        sessionId, new java.util.Date());

                logger.info("✅ 客户端 {} 已成功断开连接", sessionId);

                return McpSchema.CallToolResult.builder()
                        .content(List.of(new McpSchema.TextContent(result)))
                        .isError(false)
                        .build();
            } else {
                logger.warn("⚠️ 客户端 {} 会话未找到或已断开", sessionId);
                return McpSchema.CallToolResult.builder()
                        .content(List.of(new McpSchema.TextContent("⚠️ 会话未找到或已断开")))
                        .isError(false)
                        .build();
            }

        } catch (Exception e) {
            logger.error("❌ 处理客户端断开请求失败", e);
            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent("❌ 断开连接失败: " + e.getMessage())))
                    .isError(true)
                    .build();
        }
    }

    /**
     * 处理向指定客户端发送消息的请求
     */
    private McpSchema.CallToolResult handleSendToClient(McpSyncServerExchange exchange,
                                                        McpSchema.CallToolRequest request) {
        String sessionId = (String) request.arguments().get("session_id");
        String title = (String) request.arguments().get("title");
        String message = (String) request.arguments().get("message");

        logger.info("📤 向指定客户端发送消息 - 会话ID: {}, 标题: {}, 内容: {}", sessionId, title, message);

        try {
            // 检查客户端是否在线
            if (!transportProvider.isClientConnected(sessionId)) {
                return McpSchema.CallToolResult.builder()
                        .content(List.of(new McpSchema.TextContent("❌ 客户端不在线: " + sessionId)))
                        .isError(true)
                        .build();
            }

            // 创建消息参数
            Map<String, Object> params = Map.of(
                    "sessionId", sessionId,
                    "title", title,
                    "message", message,
                    "timestamp", System.currentTimeMillis()
            );

            // 向指定客户端发送消息
            sendToClient(sessionId, "notifications/message", params);

            String result = String.format("✅ 消息发送成功!\n" +
                            "🎯 目标客户端: %s\n" +
                            "📣 标题: %s\n" +
                            "📝 内容: %s\n" +
                            "⏰ 时间: %s",
                    sessionId, title, message, new java.util.Date());

            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent(result)))
                    .isError(false)
                    .build();

        } catch (Exception e) {
            logger.error("❌ 向客户端发送消息失败", e);
            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent("❌ 发送消息失败: " + e.getMessage())))
                    .isError(true)
                    .build();
        }
    }

    /**
     * 处理获取在线客户端列表的请求
     */
    private McpSchema.CallToolResult handleGetConnectedClients(McpSyncServerExchange exchange,
                                                               McpSchema.CallToolRequest request) {
        logger.info("📋 获取在线客户端列表");

        try {
            List<String> clientIds = transportProvider.getConnectedClientIds();

            String result;

            if (clientIds.isEmpty()) {
                result = "📭 当前没有客户端在线";
            } else {
                // 使用 JSON 序列化生成正确的 JSON 格式
                String clientIdsJson = jsonMapper.writeValueAsString(clientIds);
                logger.info("📋 获取在线客户端列表: " + clientIdsJson);
                // 对象格式: {"sessionIds": [...]}
                result = String.format("{\"sessionIds\": %s}", clientIdsJson);
            }

            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent(result)))
                    .isError(false)
                    .build();

        } catch (Exception e) {
            logger.error("❌ 获取客户端列表失败", e);
            return McpSchema.CallToolResult.builder()
                    .content(List.of(new McpSchema.TextContent("❌ 获取客户端列表失败: " + e.getMessage())))
                    .isError(true)
                    .build();
        }
    }

    /**
     * 向所有连接的客户端广播消息
     *
     * @param method 通知方法名
     * @param params 通知参数
     */
    public void broadcastToAllClients(String method, Object params) {
        if (transportProvider != null) {
            try {
                // 使用日志消息机制发送自定义通知（绕过SDK限制）
                // 将自定义通知数据转换为JSON字符串
                Map<String, Object> notificationData = Map.of("method", method, "params", params);
                String dataJson = jsonMapper.writeValueAsString(notificationData);
                
                McpSchema.LoggingMessageNotification logNotification = 
                    new McpSchema.LoggingMessageNotification(
                        McpSchema.LoggingLevel.INFO,
                        "CustomNotification",  // 特殊的logger名称，用于标识自定义通知
                        dataJson  // 必须是JSON字符串
                    );
                transportProvider.notifyClients(McpSchema.METHOD_NOTIFICATION_MESSAGE, logNotification).block();
                logger.info("📢 已向所有客户端广播消息 - 方法: {}", method);
            } catch (Exception e) {
                logger.error("❌ 广播消息失败", e);
            }
        } else {
            logger.warn("⚠️ TransportProvider 未初始化，无法广播消息");
        }
    }

    /**
     * 向指定客户端发送消息
     *
     * @param sessionId 客户端会话ID
     * @param method    通知方法名
     * @param params    通知参数
     */
    public void sendToClient(String sessionId, String method, Object params) {
        if (transportProvider != null) {
            try {
                // 使用日志消息机制发送自定义通知（绕过SDK限制）
                // 将自定义通知数据转换为JSON字符串
                Map<String, Object> notificationData = Map.of("method", method, "params", params);
                String dataJson = jsonMapper.writeValueAsString(notificationData);
                
                McpSchema.LoggingMessageNotification logNotification = 
                    new McpSchema.LoggingMessageNotification(
                        McpSchema.LoggingLevel.INFO,
                        "CustomNotification",  // 特殊的logger名称，用于标识自定义通知
                        dataJson  // 必须是JSON字符串
                    );
                transportProvider.notifyClient(sessionId, McpSchema.METHOD_NOTIFICATION_MESSAGE, logNotification).block();
                logger.info("📤 已向客户端 {} 发送消息 - 方法: {}", sessionId, method);
            } catch (RuntimeException e) {
                logger.error("❌ 向客户端 {} 发送消息失败", sessionId, e);
                throw e;
            } catch (Exception e) {
                logger.error("❌ 向客户端 {} 发送消息失败", sessionId, e);
                throw new RuntimeException("发送消息失败", e);
            }
        } else {
            logger.warn("⚠️ TransportProvider 未初始化，无法发送消息");
            throw new IllegalStateException("TransportProvider 未初始化");
        }
    }
}
